In Control flow§
See primary documentation in context for gather/take
gather
is a statement or block prefix that returns a sequence of values. The values come from calls to take in the dynamic scope of the gather
code. In the following example, we implement a subroutine to compute the factors of an integer with gather
(note that the factors are not generated in order):
sub factors( Int:D \n ) { my $k = 1; gather { while $k**2 < n { if n %% $k { take $k; take n div $k; } $k++; } take $k if $k**2 == n; } } say factors(36); # OUTPUT: «1, 36, 2, 18, 3, 12, 4, 9, 6»
The gather/take
combination can generate values lazily, depending on context. Binding to a scalar or sigilless container will force laziness. If you want to force lazy evaluation use the lazy subroutine or method. For example:
my @vals = lazy gather { take 1; say "Produced a value"; take 2; } say @vals[0]; say 'between consumption of two values'; say @vals[1]; # OUTPUT: # 1 # between consumption of two values # Produced a value # 2
gather/take
is scoped dynamically, so you can call take
from subs or methods that are called from within gather
:
sub weird(@elems, :$direction = 'forward') { my %direction = ( forward => sub { take $_ for @elems }, backward => sub { take $_ for @elems.reverse }, random => sub { take $_ for @elems.pick(*) }, ); return gather %direction{$direction}(); } say weird(<a b c>, :direction<backward> ); # OUTPUT: «(c b a)»
If values need to be mutable on the caller side, use take-rw.
Note that the Seq
created by gather/take
may be coerced to another type. An example with assignment to a hash:
my %h = gather { take "foo" => 1; take "bar" => 2}; say %h; # OUTPUT: «{bar => 2, foo => 1}»
Note: gather/take
must not be used to collect results from react/whenever
. The whenever
block is not run from the thread that runs the gather/react
, but the thread that runs the emit
. On this thread, there is no handler for the control exception thrown by take
, causing it to error out.